/*
 * Copyright (c) 2010-2011 Josef Hardi <josef.hardi@gmail.com>
 * Copyright (c) 2010 Piotr Zagawa <piotr.zagawa@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package id.duapuluhdua.dakidaki.common;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;

/**
 *
 */
public abstract class CommonThread extends Thread
{
  private static final String TAG = "CommonThread";

  /** Fields */
  private static final Integer STATE_PAUSED = 0;
  private static final Integer STATE_RUNNING = 1;

  protected Handler mHandler;
  private Context mContext;
  private Display mDefaultDisplay;

  private volatile Boolean bIsActive = false;
  private volatile Boolean bEnabled = true;
  private volatile Boolean bStateMutex = false;
  private volatile Boolean bMutex = false;

  private Integer mState;

  /**
   * The default constructor.
   *
   * @param context
   * @param handler
   */
  public CommonThread(Context context, Handler handler)
  {
    mHandler = handler;
    mContext = context;
    mState = STATE_PAUSED;

    // Get the display
    WindowManager winManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);

    if (winManager != null) {
      mDefaultDisplay = winManager.getDefaultDisplay();
    }
  }

  /**
   * Returns the screen orientation from its natural position.
   *
   * @return the screen orientation.
   * @see Surface.ROTATION_0
   * @see Surface.ROTATION_90
   * @see Surface.ROTATION_180
   * @see Surface.ROTATION_270
   */
  public int getScreenOrientation()
  {
    if (mDefaultDisplay != null) {
      return mDefaultDisplay.getRotation();
    }
    return 0; // no rotation.
  }

  /**
   * Sets a Bundle of arbitrary data values to parent handler. Returns true if
   * the message was successfully placed in to the message queue or false if
   * it is failed.
   *
   * @param bundle data values
   * @return true if it is succeeded, or false otherwise.
   */
  public boolean sendMessageToParent(Bundle bundle)
  {
    Message msg = mHandler.obtainMessage();
    msg.setData(bundle);
    return mHandler.sendMessage(msg);
  }

  /**
   * Creates and starts an execution of a new thread.
   */
  public void createThread()
  {
    bIsActive = true;
    this.start();
  }

  /**
   * Destroys a thread.
   */
  public void destroyThread()
  {
    synchronized(bMutex)
    {
      bIsActive = false;
    }

    boolean bRetry = true;
    while (bRetry) {
      try {
        this.join();
        bRetry = false;
      }
      catch (InterruptedException e) {
        Log.e(TAG, e.getMessage());
      }
    }
  }

  /**
   * Returns whether the thread is active or not.
   *
   * @return true if is is active, or false otherwise.
   */
  public boolean isActive()
  {
    synchronized(bMutex)
    {
      return bIsActive;
    }
  }

  /**
   * Activates the thread.
   *
   * @param enabled the activation status.
   */
  public void setEnabled(boolean enabled)
  {
    synchronized(bMutex)
    {
      bEnabled = enabled;
    }
  }

  /**
   * Returns the thread activation status.
   *
   * @return true if the thread is active, or false otherwise.
   */
  public boolean isEnabled()
  {
    synchronized(bMutex)
    {
      return bEnabled;
    }
  }

  /**
   * Executes the thread.
   */
  @Override
  public void run()
  {
    onInitializeData();
    super.run();
  }

  /**
   * Sets the thread to get running.
   */
  public void setStateRunning()
  {
    setState(STATE_RUNNING);
  }

  /**
   * Sets the thread to get paused.
   */
  public void setStatePaused()
  {
    setState(STATE_PAUSED);
  }

  /** Set the status of the thread */
  private void setState(Integer state)
  {
    if (!isActive()) return;

    synchronized(bStateMutex)
    {
      mState = state;

      if (mState.equals(STATE_PAUSED)) {
        Log.i(TAG, "The thread has been paused.");
      }
      if (mState.equals(STATE_RUNNING)) {
         Log.i(TAG, "The thread has been continued running.");
      }
      onStateChanged();
    }
  }

  /**
   * Returns the running status of the thread.
   *
   * @return true if the thread is running, or false otherwise.
   */
  public boolean isRunning()
  {
    boolean bValue = false;
    synchronized(bStateMutex)
    {
      bValue = (mState.equals(STATE_RUNNING));
    }
    return bValue;
  }

  // Implements something before the thread runs.
  public abstract void onInitializeData();

  // Implements something after the thread state has changed.
  public abstract void onStateChanged();

}